{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "许多AI应用需要在多个交互中共享上下文(会话历史)。在LangGraph中，这种内存可以通过线程级持久性添加到任何StateGraph。在创建任何LangGraph图时，可以通过在编译graph时添加一个检查点来设置graph的状态持久性。\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "f2b64f5446f56698"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "\n",
    "from typing_extensions import TypedDict\n",
    "from langgraph.graph import StateGraph, MessagesState\n",
    "from langgraph.constants import START\n",
    "\n",
    "class SubgraphState(TypedDict):\n",
    "    foo:str\n",
    "    bar:str\n",
    "    \n",
    "def subgraph_node_1(state:SubgraphState):\n",
    "    return {\"bar\":\"bar\"}\n",
    "\n",
    "def subgraph_node_2(state:SubgraphState):\n",
    "    # note that this node is using a state key ('bar') that is only available in the subgraph\n",
    "    # and is sending update on the shared state key ('foo')\n",
    "    return {\"foo\": state[\"foo\"] + state[\"bar\"]}\n",
    "\n",
    "subgraph_builder = StateGraph(SubgraphState)\n",
    "subgraph_builder.add_node(subgraph_node_1)\n",
    "subgraph_builder.add_node(subgraph_node_2)\n",
    "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n",
    "subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n",
    "subgraph = subgraph_builder.compile()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-04T09:13:06.170734Z",
     "start_time": "2024-11-04T09:13:04.393431Z"
    }
   },
   "id": "29b52c19548c1c87",
   "execution_count": 1
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "# parent graph\n",
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    foo: str\n",
    "\n",
    "\n",
    "def node_1(state: State):\n",
    "    return {\"foo\": \"hi! \" + state[\"foo\"]}\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"node_1\", node_1)\n",
    "# note that we're adding the compiled subgraph as a node to the parent graph\n",
    "builder.add_node(\"node_2\", subgraph)\n",
    "builder.add_edge(START, \"node_1\")\n",
    "builder.add_edge(\"node_1\", \"node_2\")\n",
    "\n",
    "checkpointer = MemorySaver()\n",
    "# You must only pass checkpointer when compiling the parent graph.\n",
    "# LangGraph will automatically propagate the checkpointer to the child subgraphs.\n",
    "graph = builder.compile(checkpointer=checkpointer)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-04T09:13:57.474506Z",
     "start_time": "2024-11-04T09:13:57.461778Z"
    }
   },
   "id": "ab58d529ec25c859",
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Verify persistence works\n"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "7fc68125ac5c1b5a"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'node_1': {'foo': 'hi! foo'}}\n",
      "{'subgraph_node_1': {'bar': 'bar'}}\n",
      "{'subgraph_node_2': {'foo': 'hi! foobar'}}\n",
      "{'node_2': {'foo': 'hi! foobar'}}\n"
     ]
    }
   ],
   "source": [
    "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "\n",
    "for _, chunk in graph.stream({\"foo\": \"foo\"}, config, subgraphs=True):\n",
    "    print(chunk)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-04T09:15:12.522523Z",
     "start_time": "2024-11-04T09:15:12.499660Z"
    }
   },
   "id": "33c7232539ca588",
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "source": [
    "继续进行会话"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "7daea199eed717b1"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "{'foo': 'hi! foobar'}"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.get_state(config).values\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-04T09:16:10.037161Z",
     "start_time": "2024-11-04T09:16:10.029050Z"
    }
   },
   "id": "242b2bace3cf5f56",
   "execution_count": 5
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'graph' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mNameError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[0;32mIn[1], line 2\u001B[0m\n\u001B[1;32m      1\u001B[0m state_with_subgraph \u001B[38;5;241m=\u001B[39m [\n\u001B[0;32m----> 2\u001B[0m     s \u001B[38;5;28;01mfor\u001B[39;00m s \u001B[38;5;129;01min\u001B[39;00m graph\u001B[38;5;241m.\u001B[39mget_state_history(config) \u001B[38;5;28;01mif\u001B[39;00m s\u001B[38;5;241m.\u001B[39mnext \u001B[38;5;241m==\u001B[39m (\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mnode_2\u001B[39m\u001B[38;5;124m\"\u001B[39m,)\n\u001B[1;32m      3\u001B[0m ][\u001B[38;5;241m0\u001B[39m]\n\u001B[1;32m      5\u001B[0m subgraph_config \u001B[38;5;241m=\u001B[39m state_with_subgraph\u001B[38;5;241m.\u001B[39mtasks[\u001B[38;5;241m0\u001B[39m]\u001B[38;5;241m.\u001B[39mstate\n\u001B[1;32m      6\u001B[0m subgraph_config\n",
      "\u001B[0;31mNameError\u001B[0m: name 'graph' is not defined"
     ]
    }
   ],
   "source": [
    "state_with_subgraph = [\n",
    "    s for s in graph.get_state_history(config) if s.next == (\"node_2\",)\n",
    "][0]\n",
    "\n",
    "subgraph_config = state_with_subgraph.tasks[0].state\n",
    "subgraph_config"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-07T01:47:21.849740Z",
     "start_time": "2024-11-07T01:47:21.405088Z"
    }
   },
   "id": "80fc7c0acc9e87",
   "execution_count": 1
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
